package com.juicygames.framework.gamepart;

import java.util.ArrayList;
import java.util.List;

import com.juicygames.framework.GameAction;
import com.juicygames.framework.exception.GameActionNotHandled;
import com.juicygames.framework.exception.GamePartNotFound;

public abstract class GamePart {
	private static final String LOGTAG = GamePart.class.getName();
	
	protected GamePart parent = null;
	protected GameEntity entity = null;
	private SubPartComponent subParts = null;
	private HandlersComponent handlers = null;
	
	public void load() {}
	
	public GamePart getWorld() {
		if (parent == null) {
			return this;
		} else {
			return parent.getWorld();
		}
	}
	
	public <G extends GamePart> G addPart(G part) {
		part.parent = this;
		
		part.load();
		
		addSubPart(part);
		
		if (part instanceof GameHandler) {
			addHandler((GameHandler)part);
		}
		
		return part;
	}
		
	private <G extends GamePart> G addSubPart(G part) {
		if (subParts == null) {
			subParts = new SubPartComponent(this);
		}
		
		return subParts.addPart(part);
	}
	
	public <PartTypeParam extends GamePart> PartTypeParam getPart(Class<PartTypeParam> partClass) {
		if (subParts == null) {
			throw new GamePartNotFound(this.toString() + " has no sub parts to find " + partClass.toString());
		}
		
		return subParts.getPart(partClass);
	}
	
	public <PartTypeParam extends GamePart> PartTypeParam tryToGetPart(Class<PartTypeParam> partClass) {
		if (subParts == null) {
			return null;
		}
		
		return subParts.tryToGetPart(partClass);
	}
	
	public <G extends GamePart> boolean containsPart(GamePart part) {
		if (subParts == null) {
			return false;
		}
		
		return subParts.containsPart(part);
	}
	
	public boolean hasPartClass(Class<? extends GamePart> partClass) {
		return tryToGetPart(partClass) != null;
	}
	
	public <G extends GamePart> List<G> getParts(Class<G> partClass) {
		if (subParts == null) {
			return new ArrayList<G>();
		}
		
		return subParts.getParts(partClass);
	}
	
	private <HandlerTypeParam extends GameHandler> HandlerTypeParam addHandler(HandlerTypeParam handler) {
		if (handlers == null) {
			handlers = new HandlersComponent(this);
		}
		
		return handlers.addHandler(handler);
	}
	
	public void handleAction(GameAction action) throws GameActionNotHandled {
		if (handlers == null) {
			throw new GameActionNotHandled(this.toString() + " has no handlers to handle " + action.toString());
		}
		
		handlers.handleAction(action);
	}
	
	public boolean tryToHandleAction(GameAction action) {
		if (handlers == null) {
			return false;
		}
		
		return handlers.tryToHandleAction(action);
	}
	
	public void destroyPart(GamePart part) {
		subParts.destroyPart(part);
		if (part instanceof GameHandler) {
			handlers.destroyHandler((GameHandler)part);
		}
	}
	
	public ActionForwarder groundHandler(GameHandler handler) {
		ActionForwarder forwarderHandler = null;
		if (parent != null) {
			forwarderHandler = new ActionForwarder(this, handler.getActionClassHandled());
			for (ActionForwarder otherForwarder : parent.getSubParts().getParts(ActionForwarder.class)) {
				if (forwarderHandler.equals(otherForwarder)) {
					return null; //break
				}
			}
			parent.addPart(forwarderHandler);
			parent.groundHandler(forwarderHandler);
		}
		return forwarderHandler;
	}
	
	public GameEntity getComponentEntity() {
		if (entity == this) {
			return (GameEntity)this;
		} else if (parent != null) {
			return parent.getComponentEntity();
		} else {
			return null;
		}
	}
	
	protected void setEntity(GameEntity entity) {
		this.entity = entity;
	}
	
	protected SubPartComponent getSubParts() {
		return subParts;
	}

}
